﻿
Imports osi.root.connector
Imports osi.root.formation
Imports osi.root.event
Imports osi.root.lock
Imports osi.root.procedure
Imports osi.root.utils

Public Class async_preparer(Of T)
    Private ReadOnly finish_get As signal_event
    Private ReadOnly d As Func(Of pointer(Of T), event_comb)
    Private initialized As Boolean
    Private v As T

    Private Sub New(ByVal initialized As Boolean)
        Me.initialized = initialized
        Me.d = Nothing
        Me.v = Nothing
        If initialized Then
            Me.finish_get = Nothing
        Else
            Me.finish_get = New signal_event()
        End If
    End Sub

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(ByVal d As Func(Of pointer(Of T), event_comb))
        Me.New(False)
        assert(Not d Is Nothing)
        Me.d = d
        start_prepare()
    End Sub

    Public Sub New(ByVal v As T)
        Me.New(True)
        assert(Not v Is Nothing)
        Me.v = v
    End Sub

    Protected Overridable Function prepare(ByVal p As pointer(Of T)) As event_comb
        assert(Not d Is Nothing)
        Return d(p)
    End Function

    Private Sub start_prepare()
        assert(Not initialized)
        assert(Not finish_get Is Nothing)
        assert(v Is Nothing OrElse is_valuetype(Of T)())
        Dim ec As event_comb = Nothing
        Dim r As pointer(Of T) = Nothing
        assert_begin(New event_comb(Function() As Boolean
                                        r = New pointer(Of T)()
                                        ec = prepare(r)
                                        Return waitfor(ec) AndAlso
                                               goto_next()
                                    End Function,
                                    Function() As Boolean
                                        If ec.end_result() Then
                                            v = (+r)
                                        End If
                                        initialized = True
                                        finish_get.mark()
                                        Return goto_end()
                                    End Function))
    End Sub

    Public Function alive() As Boolean
        Return initialized
    End Function

    Public Function [get](ByRef r As T) As Boolean
        If alive() Then
            r = v
            Return True
        Else
            Return False
        End If
    End Function

    Public Function [get](ByVal r As pointer(Of T)) As event_comb
        Return New event_comb(Function() As Boolean
                                  If initialized Then
                                      Return eva(r, v) AndAlso
                                             goto_end()
                                  Else
                                      assert(Not finish_get Is Nothing)
                                      Return waitfor(finish_get) AndAlso
                                             goto_next()
                                  End If
                              End Function,
                              Function() As Boolean
                                  Return eva(r, v) AndAlso
                                         goto_end()
                              End Function)
    End Function
End Class
